<?php
/**
 * @package security
 * @author  Matt Clayworth
 * copyright Copyright 2010 Philip Clarke / Bouncing Ltd
 * copyright Copyright 2009 Mattt Clayworth
 * @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
 */


class smz_filesystem {

  var $pnc = false; // permissions not changeable.
  var $dnw = false; // directory not writeable
  var $version = '1.0.0' ;

  function stat($dir=false){
    if($dir){
      if(@chmod($dir, SECURITY_DIR_UNLOCKED)==false){
	$this->pnc = true;
      }
      if(!is_writeable($dir)){
	$this->dnw = true;
      }
      @chmod($dir, SECURITY_DIR_LOCKED);
    }
  }

  function unlock($itm, $dirperms = SECURITY_DIR_UNLOCKED, $fileperms = SECURITY_FILE_UNLOCKED){
    if(is_dir($itm)){
      @chmod($itm, $dirperms);
    }else
    if(file_exists($itm)){
      @chmod($itm, $fileperms);
    }
    return is_writeable($itm) ;
  }

  function relock($itm, $dirperms = SECURITY_DIR_LOCKED, $fileperms = SECURITY_FILE_LOCKED){
    if(is_dir($itm)){
      @chmod($itm, $dirperms);
    }else{
      @chmod($itm, $fileperms);
    }
    return !is_writeable($itm) ;
  }

  function relockRecursive($directory, $dirperms = SECURITY_DIR_LOCKED, $fileperms = SECURITY_FILE_LOCKED){
    $array_items = array();
    if(!is_dir($directory)){
	$directory = dirname($directory);
    }
      if ($handle = @opendir($directory)) {
	while (false !== ($tmpfile = readdir($handle))) {
	  if ($tmpfile != "." && $tmpfile != "..") {
	    if (is_dir($directory. "/" . $tmpfile)) {
	      $array_items = array_merge($array_items, $this->relockRecursive($directory. "/" . $tmpfile, $dirperms, $fileperms));
	      $tmpfile = $directory . "/" . $tmpfile;
	      @chmod($tmpfile, $dirperms);
	      $array_items[] = preg_replace("/\/+/si", "/", $tmpfile);
	    } else {
	      $tmpfile = $directory . "/" . $tmpfile;
	      @chmod($tmpfile, $fileperms);
	      $array_items[] = preg_replace("/\/+/si", "/", $tmpfile);
	    }
	  }
	}
	  closedir($handle);
	}
	unset($handle);
	unset($tmpfile);

	@chmod($directory, $dirperms);
	return $array_items;
  }

  function unlockRecursive($directory, $dirperms = SECURITY_DIR_UNLOCKED, $fileperms = SECURITY_FILE_UNLOCKED){
    return $this->relockRecursive($directory, $dirperms, $fileperms);
  }


  function smartCopy($source, $dest, $folderPermission = SECURITY_DIR_UNLOCKED, $filePermission = SECURITY_FILE_UNLOCKED){
  # source=file & dest=dir => copy file from source-dir to dest-dir
  # source=file & dest=file / not there yet => copy file from source-dir to dest and overwrite a file there, if present

  # source=dir & dest=dir => copy all content from source to dir
  # source=dir & dest not there yet => copy all content from source to a, yet to be created, dest-dir

      $result=false;

      if (is_file($source)) { # $source is file
	  if(is_dir($dest)) { # $dest is folder
	      if ($dest[strlen($dest)-1]!='/') # add '/' if necessary
		$__dest=$dest."/";
		$__dest .= basename($source);
	      }
	  else { # $dest is (new) filename
	      $__dest=$dest;
	      }
	  if( !is_writeable($__dest) ){
	    $this->unlock($__dest);
	  }
	  if( !is_writeable( dirname($__dest) ) ){
	    $this->unlock(dirname($__dest));
	  }

	  $result=copy($source, $__dest);

	  @chmod($__dest, $filePermission);
	  }
      elseif(is_dir($source)) { # $source is dir
	  if(!is_dir($dest)) { # dest-dir not there yet, create it
	      $this->unlockRecursive(dirname($dest) );
	      mkdir($dest,$folderPermission);
	      @chmod($dest,$folderPermission);
// 	      $this->relock(dirname($dest) );
	      }
	  if ($source[strlen($source)-1]!='/') # add '/' if necessary
	      $source=$source."/";
	  if ($dest[strlen($dest)-1]!='/') # add '/' if necessary
	      $dest=$dest."/";

	  # find all elements in $source
	  $result = true; # in case this dir is empty it would otherwise return false
	  $dirHandle=opendir($source);
	  while($file=readdir($dirHandle)) { # note that $file can also be a folder
	      if($file!="." && $file!="..") { # filter starting elements and pass the rest to this function again
		  $result=$this->smartCopy($source.$file, $dest.$file, $folderPermission, $filePermission);
		  }
	      }
	  closedir($dirHandle);
	  }
      else {
	  $result=false;
	  }
      return $result;
  }

  function copy($file, $dest){

    if(is_dir($dest)){
      $dest = $dest.'/'.basename($file);
    }
    copy($file, $dest);

  }

  function unzip($dest, $file){

    $zip = new ZipArchive;
    if ($zip->open($file) === true) {
	$this->unlockRecursive($dest);
	$zip->extractTo($dest);
	$this->relockRecursive($dest);
	$zip->close();
      return true;
    }else{
      return false;
    }

  }

  function all_file_system($directory='.', $regex=false) {
    $array_items = array();
    if ($handle = @opendir($directory)) {
      while (false !== ($tmpfile = readdir($handle))) {
	if ($tmpfile != "." && $tmpfile != "..") {
	  if (is_dir($directory. "/" . $tmpfile)) {
	    $array_items = array_merge($array_items, $this->all_file_system($directory. "/" . $tmpfile, $regex));
	    $tmpfile = $directory . "/" . $tmpfile;
	    $array_items[] = preg_replace("/\/+/si", "/", $tmpfile);
	  } else {
	    $tmpfile = $directory . "/" . $tmpfile;
	    $array_items[] = preg_replace("/\/+/si", "/", $tmpfile);
	  }
	}
      }
	closedir($handle);
      }
      unset($handle);
      unset($tmpfile);
      if($regex){
	foreach($array_items as $key=>$val){
	  if(!preg_match('/'.$regex.'/',$val)){
	    unset($array_items[$key]);
	  }
	}
      }
      return $array_items;
  }

  function unlinkRecursive($dir){
    foreach($this->all_file_system($dir) as $itm){
      if(is_dir($itm)){
	@chmod(dirname($itm), SECURITY_DIR_UNLOCKED);
	@chmod($itm, SECURITY_DIR_UNLOCKED);
	@rmdir($itm);
      }else{
	@chmod(dirname($itm), SECURITY_DIR_UNLOCKED);
	@chmod($itm, SECURITY_FILE_UNLOCKED);
	@unlink($itm);
      }
    }
    @chmod(dirname($dir), SECURITY_DIR_UNLOCKED);
    @chmod($dir, SECURITY_DIR_UNLOCKED);
    @rmdir($dir);
    $this->relock(dirname($dir));
  }


}
